// 棋子种类
#[derive(Copy, Clone, Eq, Hash, PartialEq, Debug)]
pub enum Piece {
    // 帅 将 G
    General = 1,

    // 仕 士 A
    Advisor,

    // 相 象 E
    Elephant,

    // 马 马 H
    Horse,

    // 车 车 R
    Rook,

    // 炮 炮 C
    Cannon,

    // 兵 卒 P
    Pawn,
}

impl Piece {
    pub fn to_char(&self) -> u8 {
        match self {
            Piece::General => b'G',
            Piece::Advisor => b'A',
            Piece::Elephant => b'E',
            Piece::Horse => b'H',
            Piece::Rook => b'R',
            Piece::Cannon => b'C',
            Piece::Pawn => b'P',
        }
    }
    pub fn from_char(c: u8) -> Option<Self> {
        match c {
            b'G' => Some(Piece::General),
            b'A' => Some(Piece::Advisor),
            b'E' => Some(Piece::Elephant),
            b'H' => Some(Piece::Horse),
            b'R' => Some(Piece::Rook),
            b'C' => Some(Piece::Cannon),
            b'P' => Some(Piece::Pawn),
            _ => None,
        }
    }
}

impl TryFrom<&str> for Piece {
    type Error = &'static str;
    fn try_from(value: &str) -> Result<Self, Self::Error> {
        if value.len() > 0 {
            Piece::from_char(value.as_bytes()[0]).ok_or("Not a piece")
        } else {
            Err("Not a piece")
        }
    }
}

// 棋子颜色
#[derive(Copy, Clone, Eq, Hash, PartialEq, Debug)]
pub enum Color {
    Red = 1,
    Black,
}

impl Default for Color {
    fn default() -> Self {
        Color::Red
    }
}

impl Color {
    pub fn opponent(&self) -> Color {
        match self {
            Color::Red => Color::Black,
            Color::Black => Color::Red,
        }
    }
    pub fn to_char(&self) -> u8 {
        match self {
            Color::Red => b'R',
            Color::Black => b'B',
        }
    }
    pub fn from_char(c: u8) -> Option<Self> {
        match c {
            b'R' => Some(Color::Red),
            b'B' => Some(Color::Black),
            _ => None,
        }
    }
}

impl TryFrom<&str> for Color {
    type Error = &'static str;
    fn try_from(value: &str) -> Result<Self, Self::Error> {
        if value.len() > 0 {
            Color::from_char(value.as_bytes()[0]).ok_or("Not a color")
        } else {
            Err("Not a color")
        }
    }
}

// 棋子位置
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Pos(pub u8);

impl Pos {
    pub fn index(&self) -> usize {
        self.0 as usize
    }

    pub fn row_col(&self) -> (i8, i8) {
        ((self.0 / 9) as i8, (self.0 % 9) as i8)
    }

    pub fn from_row_col((row, col): (i8, i8)) -> Option<Pos> {
        if row >= 0 && row <= 9 && col >= 0 && col <= 8 {
            Some(Pos((row * 9 + col) as u8))
        } else {
            None
        }
    }
}

impl std::fmt::Display for Pos {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "{}", self.0)
    }
}
